package com.wdy.golden.tinysql.util;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.apache.commons.lang3.ObjectUtils;

import com.wdy.golden.tinysql.exception.TinySqlException.SqlParseException;
import com.wdy.golden.tinysql.extend.ResultColumnArrayList;
import com.wdy.golden.tinysql.mapping.Script;

/**  
 * @author Dongye_Wu
 * @version: 1.0.0
 * @Description: TODO
 * @date 2020年4月11日 下午3:39:23 
 */
public class ClazzUtil extends ObjectUtils {
	
	public static final String[] supportedListType = {"List", "ArrayList", "LinkedList", "Vector", "Stack", "ResultColumnArrayList"};
	public static final String[] supportedMapType = {"Map", "HashMap", "LinkedHashMap", "WeakHashMap", "TreeMap", "IdentityHashMap", "HashTable"};
	
	/**
	 * 是否自定义类型
	 * @param obj
	 * @return
	 */
	public static boolean isCustomObject(Object obj) {
		return isCustomObject(obj.getClass());
	}

	public static boolean isCustomObject(Class<?> clazz) {
		if(clazz.getClassLoader()==null) {//jdk核心类为null
			return false;
		}
		return true;
	}
	
	/**
	 * 是否基础数据类型
	 * @param clazz
	 * @return
	 */
	public static boolean isPrimitive(Class<?> clazz) {
		if(clazz.isPrimitive()) {
			return true;
		}
		return false;
	}
	
	/**
	 * 是否是基础数据类型的封装类
	 * @param clazz
	 * @return
	 */
	public static boolean isWrapClass(Class<?> clazz) {
		try {
			return ((Class<?>) clazz.getField("TYPE").get(null)).isPrimitive();
		} catch (Exception e) {
			return false;
		}
	}
	
	public static boolean isPrimitiveOrWrap(Class<?> clazz) {
		if(isPrimitive(clazz)) {
			return true;
		}else if(isWrapClass(clazz)) {
			return true;
		}		
		return false;
	}
	
	public static boolean isSpecialClassType(Class<?> clazz, String type) {
		if(type.equals(clazz.getSimpleName())) {
			return true;
		}
		return false;
	}
	
	public static boolean isVoid(Class<?> clazz) {
		return isSpecialClassType(clazz, "void");
	}
	
	public static boolean isList(Class<?> clazz) {
		for(String listType : supportedListType) {
			if(isSpecialClassType(clazz, listType)) {
				return true;
			}
		}
		return false;
	}

	public static boolean isMap(Object obj) {
		return isMap(obj.getClass());
	}
	
	public static boolean isMap(Class<?> clazz) {
		for(String listType : supportedMapType) {
			if(isSpecialClassType(clazz, listType)) {
				return true;
			}
		}
		return false;
	}
	
	public static Class<?> getListGenericReturnType(Method method) throws SqlParseException{
		Class<?> returnType = method.getReturnType();
		if (isList(returnType)){
            Type type = method.getGenericReturnType();
            if (type instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
                String typeName = actualTypeArguments[0].getTypeName();
                Class<?> actualType = null;
				try {
					actualType = Class.forName(typeName);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
					throw new SqlParseException("[Tinysql] Generic type of list is not found, error: "+ e.getMessage());
				}
                return actualType;
            }
        }
		throw new SqlParseException("[Tinysql] Return type is not a List.");
	}
	
	public static boolean isResultColumnArrayList(Class<?> clazz) {
		if(clazz == ResultColumnArrayList.class) {
			return true;
		}
		return false;
	}
	
	public static void main(String[] args) {		
		System.out.println("-------------------------------------");
		System.out.println(ClazzUtil.isPrimitive(void.class));		
		System.out.println(ClazzUtil.isPrimitive(int.class));

		System.out.println(ClazzUtil.isWrapClass(Integer.class));
		System.out.println(ClazzUtil.isWrapClass(void.class));
		
		System.out.println(ClazzUtil.isPrimitive(Integer.class));
		System.out.println(ClazzUtil.isPrimitiveOrWrap(Script.class));

		System.out.println(ClazzUtil.isVoid(void.class));
		System.out.println(ClazzUtil.isVoid(Script.class));
		System.out.println(ClazzUtil.isVoid(Integer.class));
		System.out.println(ClazzUtil.isVoid(int.class));
		
		System.out.println("-------------------------------------");
		
		System.out.println(ClazzUtil.isCustomObject(new Script()));
		System.out.println(ClazzUtil.isCustomObject(Script.class));
		System.out.println(ClazzUtil.isCustomObject(1));
		System.out.println(ClazzUtil.isCustomObject(100L));
		System.out.println(ClazzUtil.isCustomObject(-100L));
		System.out.println(ClazzUtil.isCustomObject(-100.5698));				
		int i = 1;
		System.out.println(ClazzUtil.isCustomObject(i));
		
		System.out.println("-------------------------------------");
		
		
		Integer integer = new Integer(100);		
		System.out.println(integer.getClass().getFields());
		String str = new String("200");		
		System.out.println(str.getClass().getFields());
		Boolean bool = new Boolean(true);		
		System.out.println(bool.getClass().getFields());
	}
}
